
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#include "nsa.h"

static int16_t nsa_read_int16(FILE* fp)
{
	uint8_t buffer[2];
	if(fread(buffer, 1, 2, fp) != 2)
	{
		return -1;
	}
	else
	{
		return (((int64_t)buffer[0] <<  8) |
				((int64_t)buffer[1] <<  0));
	}
}

static int32_t nsa_read_int32(FILE* fp)
{
	uint8_t buffer[4];
	if(fread(buffer, 1, 4, fp) != 4)
	{
		return -1;
	}
	else
	{
		return (((int64_t)buffer[0] << 24) |
				((int64_t)buffer[1] << 16) |
				((int64_t)buffer[2] <<  8) |
				((int64_t)buffer[3] <<  0));
	}
}

static char* nsa_read_cstring(FILE* fp)
{
	char* buffer = malloc(256);
	int i;
	for (i = 0; i < 256; ++i)
	{
		int c = fgetc(fp);
		if (c == 0)
		{
			buffer[i] = 0;
			return buffer;
		}
		else if (c == -1)
		{
			free(buffer);
			fprintf(stderr, "EOF\n");
			return NULL;
		}
		buffer[i] = (uint8_t)c;
	}
	free(buffer);
	fprintf(stderr, "Buffer overflow!\n");
	return NULL;
}

nsa_entries_t* read_nsa_indexes(const char* nsa_path)
{
	nsa_entries_t* index = NULL;
	int n;
	int32_t global_offset;
	nsa_entry_t* entries = NULL;

	int i;

	FILE* fp = fopen(nsa_path, "rb");
	if (!fp)
	{
		fprintf(stderr, "Open %s error\n", nsa_path);
		return NULL;
	}

	n = nsa_read_int16(fp);
	global_offset = nsa_read_int32(fp);
	if (n <= 0 || global_offset <=0)
	{
		fprintf(stderr, "Invalid nsa file format\n");
		return NULL;
	}

	entries = malloc(n * sizeof(nsa_entry_t));
	for (i = 0; i < n; ++i)
	{
		entries[i].name = nsa_read_cstring(fp);
		fgetc(fp);
		entries[i].offset = global_offset + nsa_read_int32(fp);
		entries[i].size = nsa_read_int32(fp);
		if (nsa_read_int32(fp) != entries[i].size)
		{
			free(entries);
			while (i >= 0)
			{
				free(entries[i--].name);
			}
			fprintf(stderr, "size != expandsize (compress is not supported)\n");
			return NULL;
		}
	}

	index = malloc(sizeof(nsa_entries_t));
	index->entry_number = n;
	index->entries = entries;
	return index;
}

void free_nsa_indexes(nsa_entries_t* index)
{
	int i;
	if (index)
	{
		for (i = 0; i < index->entry_number; ++i)
		{
			free(index->entries[i].name);
		}
		free(index->entries);
		free(index);
	}
}

int decode_nsa_entry_in_buffer(const char* path, nsa_entry_t* entry, uint8_t* buffer)
{
	size_t n;
	FILE* fp = fopen(path, "rb");
	if (!fp)
	{
		fprintf(stderr, "Open %s error\n", path);
		return -1;
	}
	n = fread(buffer, 1, entry->size, fp);
	if (n != entry->size)
	{
		fprintf(stderr, "EOF\n");
		return -1;
	}
	return 0;
}


